//
//  Stream.m
//  QBIM
//
//  Created by liu nian on 14-3-17.
//  Copyright (c) 2014年 liunian. All rights reserved.
//

#import "Stream.h"
#import "SynthesizeSingleton.h"
#import "BodyBase.h"
#import "PacketCenter.h"

@interface Stream ()<NSStreamDelegate>

@end
static Stream *staticPacketCenterShared = nil;
@implementation Stream

#pragma mark - class
- (id)init{
    return nil;
}

- (id)initHidden{
    [self startClient];
    [self openStreams];
    return [super init];
}

+ (Stream *)sharedStream{
    if (nil == staticPacketCenterShared)
        {
        staticPacketCenterShared = [[Stream alloc] initHidden];
        }
    return staticPacketCenterShared;
}

-(void)startClient
{
    _hasEstablished = NO;
    CFReadStreamRef        readStream = NULL;
    CFWriteStreamRef    writeStream = NULL;
    NSString            *server = SERVER_DOMAIN_IM_SOCKET;

    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
                                       (CFStringRef)server,
                                       kPort_IM_SOCKET,//服务器接收数据的端口
                                       &readStream,
                                       &writeStream);
    
    
    if(readStream && writeStream)
        {
            inStream = (NSInputStream *)readStream;
            outStream = (NSOutputStream *)writeStream;
        }
    else
        {
            //Error Control
        }
}

-(void)closeStreams{
    //    [[PromptView sharedPromptView] dismissPromptView];
    [inStream close];
    [outStream close];
    [inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [inStream setDelegate:nil];
    [outStream setDelegate:nil];
    [inStream release];
    [outStream release];
    inStream = nil;
    outStream = nil;
}

-(void)openStreams{
    [inStream retain];
    [outStream retain];
//    [inStream setProperty:NSStreamSocketSecurityLevelSSLv3 forKey:NSStreamSocketSecurityLevelKey];
//    [outStream setProperty:NSStreamSocketSecurityLevelSSLv3 forKey:NSStreamSocketSecurityLevelKey];
//    //不需要SSL的话，下面这行可以去掉。
//    CFWriteStreamSetProperty((CFWriteStreamRef)outStream, kCFStreamPropertySSLSettings, [NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kCFBooleanFalse,kCFStreamSSLValidatesCertificateChain,kCFBooleanFalse,kCFStreamSSLIsServer,nil]);
    [inStream setDelegate:self];
    [outStream setDelegate:self];
    [inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [inStream open];
    [outStream open];
}

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    switch(eventCode) {
        case NSStreamEventHasBytesAvailable:
        {
        if(_isFirstFourBytes)//读取前4个字节，算出数据包大小
            {
            uint8_t bufferLen[4];
            if([inStream read:bufferLen maxLength:4] == 4)
                {
                remainingToRead = ((bufferLen[0]<<24)&0xff000000)+((bufferLen[1]<<16)&0xff0000)+((bufferLen[2]<<8)&0xff00)+(bufferLen[3] & 0xff);
                _isFirstFourBytes = NO;
                }
            else
                {
                [self closeStreams];
                //Error Control
                }
            }
        else//根据数据包大小读取数据
            {
            int actuallyRead;
            uint8_t buffer[32768];//32KB的缓冲区，缓冲区太小的话会明显影响真机上的通信速度
            if (!dataBuffer) {
                dataBuffer = [[NSMutableData alloc] init];
            }
            
            actuallyRead = [inStream read:buffer maxLength:sizeof(buffer)];
            if(actuallyRead == -1){
                [self closeStreams];
                //Error Control
            }else if(actuallyRead == 0){
                //Do something if you want
            }else{
                [dataBuffer appendBytes:buffer length:actuallyRead];
                remainingToRead -= actuallyRead;
            }
            
            if(remainingToRead == 0)
                {
                _isFirstFourBytes = YES;
                [self manageData:dataBuffer];//数据接收完毕，把数据送回调用sream的函数
                [dataBuffer release];
                dataBuffer = nil;
                }
            }
        break;
        }
        case NSStreamEventEndEncountered://连接断开或结束
        {
        [self closeStreams];
        break;
        }
        case NSStreamEventErrorOccurred://无法连接或断开连接
        {
        if([[aStream streamError] code])//确定code不是0……有时候正常使用时会跳出code为0的错误，但其实一点问题都没有，可以继续使用，很奇怪……
            {
            [self closeStreams];
            break;
            }
        }
        case NSStreamEventOpenCompleted:
        {
        _hasEstablished = YES;
        [[Stream sharedStream] requestData:@"SS" whoRequest:self condition:1];
        break;
        }
        case NSStreamEventHasSpaceAvailable:
        {
        break;
        }
        case NSStreamEventNone:
        default:
            break;
    }
}

//判断是否能连接到服务器。这个函数用来判断网络是否连通还好
-(BOOL)isServerAvailable{
    NSString *addressString = SERVER_DOMAIN_IM_SOCKET;
    if (!addressString) {
        return NO;
    }
    
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [addressString UTF8String]);
    SCNetworkReachabilityFlags flags;
    
    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    CFRelease(defaultRouteReachability);
    
    if (!didRetrieveFlags)
        {
        return NO;
        }
    
    BOOL isReachable = flags & kSCNetworkFlagsReachable;
    BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired;
    return (isReachable && !needsConnection) ? YES : NO;
}

-(void)requestData:(NSString *)requestString whoRequest:(id)currentObject condition:(int)numCondition
{
    if(![self isServerAvailable])//如果无法连通到服务器
        {
        //Error Control
        }
    else
        {
        if(inStream == nil || outStream == nil)
            {
            [[Stream sharedStream] startClient];
            [[Stream sharedStream] openStreams];
            _isFirstFourBytes = YES;
            }
        
        if(inStream != nil && outStream != nil)
            {
            _currentObject = currentObject;//记下是谁调用了requestData（记下了它的指针）
            _numCondition = numCondition;//参数，以便有时候需要区分同一个类里发来的不同请求
            if(_hasEstablished)
                {
                
                AuthBody *authParm= [AuthBody parmObj];
                authParm.I = [NSString stringWithFormat:@"%d",[[PacketCenter shared] getPacketSeqID]];
                authParm.V = @"v1.0.0";
                authParm.AT = [NSString stringWithFormat:@"%d",AuthTypeCasToken];
                authParm.AP = @"{\"COOKIE\":\"TESTCOOKIE\",\"ID\":4}";
                
                HeaderBody *body = [[HeaderBody alloc] initWithBody:authParm];
                body.packetType = PacketTypeAuthRequest;
                
                NSData *requestData = [body.bodyJSON dataUsingEncoding:NSUTF8StringEncoding];
                
                Byte ptByte[] = {body.packetType};
                Byte pfByte[] = {body.packetFormat};
                
                int32_t length = [requestData length];
                length = htonl(length);
                NSMutableData *lengthData = [NSMutableData dataWithBytes:&length length:sizeof(int32_t)];
                [lengthData appendBytes:ptByte length:1];   //追加字符串
                [lengthData appendBytes:pfByte length:1];
                
                [lengthData appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
                
                NSMutableData *data = [[NSMutableData alloc] initWithData:lengthData];
                [data appendData:requestData];
                
                
                int remainingToWrite = length+ 4;
                void * marker = (void *)[data bytes];
                int actuallyWritten;
                
                while ([outStream hasSpaceAvailable]) {
                    if (remainingToWrite > 0) {
                        actuallyWritten = 0;
                        
                        if(remainingToWrite < 32768)
                            actuallyWritten = [outStream write:marker maxLength:remainingToWrite];//不足32KB数据时发送剩余部分
                        else
                            actuallyWritten = [outStream write:marker maxLength:32768];//每次32KB数据
                        
                        if ((actuallyWritten == -1) || (actuallyWritten == 0))
                            {
                            [self closeStreams];
                            //Error control
                            }
                        else
                            {
                                remainingToWrite -= actuallyWritten;
                                marker += actuallyWritten;
                            }
                    }
                    else
                        {
                            break;
                        }
                }
                }
            else
                {
                    //Error Control
                }
            }
        }
}

-(void)manageData:(NSData *)receivedData{
    [_currentObject getData:receivedData condition:_numCondition];//执行_currentObject指针所指向的类里的getData函数，并把收到的数据传递过去
}

- (void)dealloc {
    [super dealloc];
}

@end